//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#include "rs/unittest/TestCase.hpp"
#include "rs/unittest/TestFailure.hpp"
#include "rs/unittest/TestRunner.hpp"
#include "rs/Assert.hpp"
#include "rs/ThreadLocalPtr.hpp"
#include <csetjmp>
#include <cstdlib>

namespace rs
{
    namespace unittest
    {
        namespace
        {
            ThreadLocalPtr< TestFailure > failure;
            ThreadLocalPtr< std::jmp_buf > env;
            //TestFailure failure;
            //std::jmp_buf* env;
            
            Boolean UnitTestAssertHandler(Char8 const* file, RsSize line, Char8 const* condition, Char8 const* message) {
                failure.Reset(new TestFailure(0, file, line, condition, message));
                //failure = TestFailure(0, file, line, condition, message);
                ::longjmp(*env, 1);
                return false;
            }
        }
           
        void TestCase::Run(TestRunner* runner) {
            if (env.Get() == 0) {
                env.Reset((::jmp_buf*)std::malloc(sizeof(std::jmp_buf)));
            }
            
            Assert::ReportHandler originalReportHandler = Assert::GetReportHandler();
            Assert::SetReportHandler(&UnitTestAssertHandler);
            
            int assertHappened = ::setjmp(*env);
            if (assertHappened == 1) {
                Assert::SetReportHandler(originalReportHandler);
                failure->owner = this;
                runner->ReportTestFailure(this, &(*failure));
            }
            else {
                if (failure.Get() != 0) {
                    failure->owner = 0;
                }
                
                RunImplementation();
                runner->ReportTestSuccees(this);
            }
            
            Assert::SetReportHandler(originalReportHandler);
        }
    }
}